<?php

namespace LRP;

use LRP\Contract\TubeFactoryInterface;
use LRP\Contract\WorkerInterface;
use LRP\Utils\Sys;

/**
 * Class Worker
 *
 * PHP Version > 7.0
 *
 * @package LRP
 * @author  Jon
 * @link    https://gitee.com/joncc/long-running-processor
 */
class Worker implements WorkerInterface
{
    private static $connection;

    private $tube;

    /**
     * Worker constructor.
     *
     * @param string $tube
     */
    public function __construct(string $tube)
    {
        $this->tube = $tube;
    }

    /**
     * @param string $host
     * @param int $port
     * @param int $connectTimeout
     * @return Contract\TubeInterface
     */
    public static function create(string $host = '127.0.0.1', int $port = 6379, int $connectTimeout = 0)
    {
        return self::createWithFactory(new TubeFactory($host, $port, $connectTimeout));
    }

    /**
     * @param TubeFactoryInterface $factory
     * @return Contract\TubeInterface
     */
    public static function createWithFactory(TubeFactoryInterface $factory)
    {
        self::$connection = $factory->create();
        return self::$connection;
    }

    public function start(): void
    {
        Sys::alarm();

        while (true) {
            $task = self::$connection->type($this->tube)->pop();
            if (empty($task)) {
                break;
            }

            $result = $this->work($task);

            if ($result === TASK::STATUS_OK) {
                continue;
            } elseif ($result instanceof Task) {
                self::$connection->type($this->tube)->push($result);
            } elseif (is_array($result)) {
                foreach ($result as $one_task) {
                    if ($one_task instanceof Task) {
                        self::$connection->type($this->tube)->push($one_task);
                    }
                }
            }
        }
    }

    /**
     * @param Task $task
     * @return bool|mixed
     */
    public function work(Task $task)
    {
        $tube = $task->getTube();
        $cls = Register::getHandle($tube);
        if (!$cls) {
            return false;
        }

        $handle = $task->getHandle();
        $msg = $task->getMsg();

        return call_user_func_array([(new $cls), $handle], [$msg]);
    }
}